#import "CocoaDelegate.h"
#import "CocoaLink.h"
#import "CocoaGlobals.h"
#import "CocoaType.h"
#import <MathematicaKit/MMathLink.h>
#import "mathlink.h"

@implementation CocoaDelegate

- (id) initWithContext: (MExpr*) context
	signatures: (NSDictionary*) signatures implementations: (NSDictionary*) implementations
{
	self = [super init];
	_context = [context retain];
	_sigs = [signatures copy];
	_impls = [implementations copy];
	return self;
}

- (void) dealloc
{
	[_context release];
	[_sigs release];
	[_impls release];
	[super dealloc];
}

- (BOOL) respondsToSelector: (SEL) aSelector
{
	if([_sigs valueForKey: NSStringFromSelector(aSelector)] != nil)
		return YES;
	return [super respondsToSelector: aSelector];
}

- (NSMethodSignature*) methodSignatureForSelector: (SEL) aSelector
{
	NSMethodSignature* sig;
	if(sig = [_sigs valueForKey: NSStringFromSelector(aSelector)])
		return sig;
	return [super methodSignatureForSelector: aSelector];
}

- (void) forwardInvocation: (NSInvocation*) invocation
{
	NSString* name = NSStringFromSelector([invocation selector]);
	id impl = [_impls valueForKey: name];
	if(impl)
	{
		MMathLink* link = GetLink();
		NSMutableArray* args = [NSMutableArray array];
		
		[args addObject: kSymbolList];
		[args addObject: _context];
		[args addObject: MString(name)];
		
		int i, argc = [[invocation methodSignature] numberOfArguments];
		for(i = 2; i < argc; i++)
		{
			MExpr* arg = [invocation argumentExprAtIndex: i];
			if(arg)
				[args addObject: arg];
		} 
		
		MExpr* expr = MFunction(MSymbol(@"Apply"),
			impl,
			MFunction(MSymbol(@"CocoaLink`Private`CocoaObjectInitialize"), 
				[MExpr exprWithFunctionParts: args],
				nil),
			nil);
		
		if([link newPacket]
			&& [link putFunction: @"EvaluatePacket" length: 1]
			&& [expr put: link]
			&& [link endPacket]
			&& [link flush])
		{
			unsigned long packet;
			while((packet = [link nextPacket]) != 0)
			{
				switch(packet)
				{
					case RETURNPKT:
					{
						MExpr* message;
						expr = [MExpr exprWithLink: link];
						if(![invocation setReturnExpr:expr message: &message])
						{
							[MFunction(MSymbol(@"EvaluatePacket"), message, nil) put: link];
							[link nextPacket];
						}
						return;
					}
					case MESSAGEPKT:
						expr = [MExpr exprWithLink: link];
						NSLog(@"%@", expr);
						break;
					case CALLPKT:
						MLDoCallPacket([link link]);
						break;
				}
				[link newPacket];
			}
		}
	}
	else
		[super forwardInvocation: invocation];
}

@end
